package com.ctrip.corp.obt.shard.infrastructure.mapper;

import com.ctrip.corp.obt.generic.utils.IOUtils;
import com.ctrip.corp.obt.shard.configuration.DataShardProperties;
import com.ctrip.corp.obt.shard.constants.DbType;
import com.ctrip.corp.obt.shard.core.ShardDataSource;
import com.ctrip.corp.obt.shard.domain.gateway.DataShardSourceGateway;
import com.ctrip.corp.obt.shard.holder.ShardSourceHolder;
import com.ctrip.corp.obt.shard.sql.mybatis.interceptor.dialect.DialectFactory;
import com.ctrip.corp.obt.shard.sql.mybatis.interceptor.dialect.IDialect;
import com.ctrip.corp.obt.shard.utils.JdbcUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author marco.zheng
 * @version 1.0
 * @date 2022/03/15
 * @desc mybatis 数据网关
 * @see
 * @since 1.0
 */
public class MybatisDataShardSourceGateway implements DataShardSourceGateway, InitializingBean {

    private DataShardSourceMapper dataShardSourceMapper;
    private ResourceLoader resourceLoader;
    private DataShardProperties dataShardProperties;

    private volatile boolean tableExist = false;

    @Override
    public Set<ShardDataSource> getAllSource() {
        if (!tableExist) {
            return Collections.emptySet();
        }
        return dataShardSourceMapper.selectAllSource().stream().filter(Objects::nonNull).map(ShardDataSource::build)
            .collect(Collectors.toSet());
    }

    @Override
    public Set<ShardDataSource> getSourceByTenantIds(Set<String> tenantIds) {
        if (!tableExist) {
            return Collections.emptySet();
        }
        return dataShardSourceMapper.selectSourceByTenantIdList(tenantIds).stream().filter(Objects::nonNull)
            .map(ShardDataSource::build).collect(Collectors.toSet());
    }

    @Override
    public void afterPropertiesSet() throws SQLException, IOException {
        // 初始化tableExist，根据策略创建表
        DataSource defaultDataSource = ShardSourceHolder.getDefaultDataSource();
        DbType dbType = JdbcUtils.getDbType(defaultDataSource.getConnection());
        IDialect dialect = DialectFactory.getDialect(dbType);
        String tableSearchSql = dialect.buildTableSearchSql("sharding_data_source");
        tableExist = Objects.nonNull(dataShardSourceMapper.tableExist(tableSearchSql));
        // TODO 目前只支持Mysql创建，后面需要用到多数据库再优化判断逻辑
        if (!tableExist && dbType.equals(DbType.MYSQL) && dataShardProperties.isAutoCreateSdsIfNotExist()) {
            Resource resource = resourceLoader.getResource("classpath:sharding_data_source.sql");
            String tableCreateSql = IOUtils.toString(resource.getInputStream());
            dataShardSourceMapper.tableCreate(tableCreateSql);
        }
    }

    @Autowired
    public void setDataShardSourceMapper(DataShardSourceMapper dataShardSourceMapper) {
        this.dataShardSourceMapper = dataShardSourceMapper;
    }

    @Autowired
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    @Autowired
    public void setDataShardProperties(DataShardProperties dataShardProperties) {
        this.dataShardProperties = dataShardProperties;
    }
}
